package com.acme.bankapp.domain.accounts;

import com.acme.bankapp.exception.NotEnoughFundsException;
import com.acme.bankapp.exception.OverDraftLimitExceededException;

public class CheckingAccount extends AbstractAccount {
	private double overdraft = 0;

	public CheckingAccount(double amount, double overdraft) {
		super(amount);
        this.overdraft = overdraft;
	}

    public void setOverdraft(double overdraft) {
        if (overdraft < 0) {
            throw new IllegalArgumentException("Задано отрицательное значение овердрафта");
        }
        this.overdraft = overdraft;
    }

    public double getOverdraft() {
        return overdraft;
    }

	@Override
	public double maximumAmountToWithdraw() {
		return getBalance() + getOverdraft();
	}

    @Override
    public void withdraw(double amount) throws OverDraftLimitExceededException {
        try {
            super.withdraw(amount);
        } catch (NotEnoughFundsException e) {
            throw new OverDraftLimitExceededException(maximumAmountToWithdraw());
        }
        if( getBalance() < 0 ) {
            refundBalanceFromOverdraft();
        }
        assert (getBalance() >= 0 && getOverdraft() >= 0) : "Баланс и овердрафт должны быть неотрицательными!";
    }

    private void refundBalanceFromOverdraft() {
        assert getBalance() < 0 : "This method should not be called when balance is not negative.";
        setOverdraft(getOverdraft() - Math.abs(getBalance()));
        deposit(Math.abs(getBalance()));
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        if (!super.equals(o)) return false;

        CheckingAccount that = (CheckingAccount) o;
        return that.overdraft == overdraft;
    }

    @Override
    public int hashCode() {
        int result = super.hashCode();
        long temp;
        temp = Double.doubleToLongBits(overdraft);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        return result;
    }
}
